/*
 * spi_io.c
 *
 * Created: 8/29/2013 12:09:30 PM
 *  Author: Ken Arok
 *
 * \file
 *
 * \brief Input Output Drivers for SPI.
 *
 * Copyright (c) 2013 PT Hanindo Automation Solutions. All rights reserved.
 *
 */

#include "config_peripherals.h"

#if SPI_PERIPHERAL_ACTIVE

#include "config_ROM_HW.h"
#include "rom.h"
#include "spi.h"
#include "spi_io.h"


#define SPI_SPEED_DEFAULT			1000000		//!< 1 MHz speed default.
#define SPI_DATA_LENGTH_DEFAULT		8			//!< 8 bit data width
#define SPI_DELAY_BS_DEFAULT		0			//!< default delay bcs.
#define SPI_DELAY_BCT_DEFAULT		0			//!< default delay bct.
#define SPI_KEEP_ACTIVE_DEFAULT		1			//!< default keep active (master mode).
#define SPI_MODE_DEFAULT			SPI_MODE_0;	//!< SPI mode 0
#define SPI_MASTER_SETUP_DEFAULT	true		//!< Default is master mode setup.


static spi_channel_options_t spi_opts;

void spi_io_init(void)
{
	const char _path_name[] = "SPIEXT";
	spi_descriptor_t _spi_desc;
	
	spi_opts.baudrate = SPI_SPEED_DEFAULT;
	spi_opts.bits = SPI_DATA_LENGTH_DEFAULT;
	spi_opts.delay_bs = SPI_DELAY_BS_DEFAULT;
	spi_opts.delay_bct = SPI_DELAY_BCT_DEFAULT;
	spi_opts.keep_actv = SPI_KEEP_ACTIVE_DEFAULT;
	spi_opts.spi_mode = SPI_MODE_DEFAULT;
	spi_opts.master_setup = SPI_MASTER_SETUP_DEFAULT;

	/* Initialize ROM base address pointer. */
	if(ROM_Base_Block1 == NULL) {
		/* Prepare Copy Block 1 of ROM to RAM. */
		ROM_Base_Block1 = pvPortMalloc(ROM_BLOCK_SIZE);
		if(ROM_Base_Block1 == NULL) {
			while(1);
		}

		if(vReadROM(ROM_BASE_ADDR_BLOK1, ROM_Base_Block1, ROM_BLOCK_SIZE)) {
			while(1);
		}
	}

	/* Initialize SPI. */
	spi_init();

	/* SPI option to default. */
	_spi_desc = spi_open(_path_name, 0);
	spi_setup(_spi_desc, (const spi_channel_options_t *)&spi_opts);
	spi_close(_spi_desc, 0);
}


portBASE_TYPE spi_io_ctrl(io_descriptor_t io_desc, io_request_code_t reqCode, void *pValue)
{
	portBASE_TYPE _ret_status = pdPASS;
	
	switch(reqCode) {
		case IORC_RESTART_MODULE:
			/* Initialize SPI. */
			spi_init();
		break;

		case IORC_SET_DEFAULT:
			spi_opts.baudrate = SPI_SPEED_DEFAULT;
			spi_opts.bits = SPI_DATA_LENGTH_DEFAULT;
			spi_opts.delay_bs = SPI_DELAY_BS_DEFAULT;
			spi_opts.delay_bct = SPI_DELAY_BCT_DEFAULT;
			spi_opts.keep_actv = SPI_KEEP_ACTIVE_DEFAULT;
			spi_opts.spi_mode = SPI_MODE_DEFAULT;
			spi_opts.master_setup = SPI_MASTER_SETUP_DEFAULT;
			spi_setup(io_desc, (const spi_channel_options_t *)&spi_opts);
		break;

		case IORC_SET_SPEED:
			spi_opts.baudrate = *(uint32_t *)pValue;
			spi_setup(io_desc, (const spi_channel_options_t *)&spi_opts);
		break;

		case IORC_SET_DATA_BIT:
			spi_opts.bits = *(uint8_t *)pValue;
			spi_setup(io_desc, (const spi_channel_options_t *)&spi_opts);
		break;

		case IORC_SET_MODE:
			spi_opts.spi_mode = *(uint8_t *)pValue;
			spi_setup(io_desc, (const spi_channel_options_t *)&spi_opts);
		break;

		case IORC_SET_TRANSFER_POLLED_TX:
			spi_tranfer_mode(io_desc, SPI_POLLED_TX);
		break;

		case IORC_SET_TRANSFER_POLLED_RX:
			spi_tranfer_mode(io_desc, SPI_POLLED_RX);
		break;

		case IORC_SET_TRANSFER_INTERRUPT_TX:
			spi_tranfer_mode(io_desc, SPI_INTERRUPT_TX);
		break;

		case IORC_SET_TRANSFER_INTERRUPT_RX:
			spi_tranfer_mode(io_desc, SPI_INTERRUPT_RX);
		break;

		case IORC_SET_DELAY_BS:
			spi_opts.delay_bs = *(uint8_t *)pValue;
			spi_setup(io_desc, (const spi_channel_options_t *)&spi_opts);
		break;

		case IORC_SET_DELAY_BCT:
			spi_opts.delay_bct = *(uint8_t *)pValue;
			spi_setup(io_desc, (const spi_channel_options_t *)&spi_opts);
		break;

		case IORC_SET_KEEP_ACTIVE:
			spi_opts.keep_actv = *(uint8_t *)pValue;
			spi_setup(io_desc, (const spi_channel_options_t *)&spi_opts);
		break;

		default:
			_ret_status = pdFAIL;
		break;
	}
	
	return _ret_status;
}


io_descriptor_t spi_io_open(IO_path path_name, const uint8_t flag)
{
	return spi_open(path_name, flag);
}


portBASE_TYPE spi_io_close(io_descriptor_t io_desc, const uint8_t flag)
{
	if(SPI_STATUS_OK == spi_close(io_desc, flag)) return pdPASS;

	return pdFAIL;
}


portBASE_TYPE spi_io_write(io_descriptor_t io_desc, const void *pBuf, uint32_t size, io_rw_flag_t flag)
{
	portBASE_TYPE _ret_status = pdFAIL;
	
	switch(flag) {
		case IORWF_BYTE_ORDER:
			if(SPI_STATUS_OK == spi_write_byte(io_desc, pBuf, size)) {
				_ret_status = pdPASS;
			}
		break;

		case IORWF_WORD_ORDER:
			if(SPI_STATUS_OK == spi_write_word(io_desc, pBuf, size)) {
				_ret_status = pdPASS;
			}
		break;
		
		default: break;
	}
	
	return _ret_status;
}


portBASE_TYPE spi_io_read(io_descriptor_t io_desc, void *pBuf, uint32_t size, io_rw_flag_t flag)
{
	portBASE_TYPE _ret_status = pdFAIL;

	switch(flag) {
		case IORWF_BYTE_ORDER:
			if(SPI_STATUS_OK == spi_read_byte(io_desc, pBuf, size)) {
				_ret_status = pdPASS;
			}
		break;

		case IORWF_WORD_ORDER:
			if(SPI_STATUS_OK == spi_read_word(io_desc, pBuf, size)) {
				_ret_status = pdPASS;
			}
		break;

		default: break;
	}
	
	return _ret_status;
}

#endif /* SPI_PERIPHERAL_ACTIVE */
